/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 *
 */

import { cloneDeep } from '@baize/wdk';
import { projectOhosConfigManager } from '../common/global/project-ohos-config-manager.js';
import { CommonConst } from '../const/common-const';
import { ProjectModelImpl } from '../model/project/project-model-impl.js';
import { AppOpt } from '../options/build/app-ohos-config.js';
import { AppJson } from '../options/configure/app-json-options.js';
import AppOptObj = AppJson.AppOptObj;
import { PackingToolOptions } from '../builder/inner-java-command-builder/packing-tool-options.js';
import { findTargetProduct } from '../common/find-target-product.js';
import { ProjectModel } from '../model/project/project-model.js';
import { ProjectBuildProfile } from '../options/build/project-build-profile.js';
import ProductBuildOpt = ProjectBuildProfile.ProductBuildOpt;
import fse from 'fs-extra';
import path from 'path';

import { BuildArtifactConst } from '../const/build-directory-const.js';

import { getJson5Obj } from './json-util.js';
import { OhosLogger } from './log/ohos-logger';
import RemoteHspOpt = ProjectBuildProfile.RemoteHspOpt;

export interface IntegratedRemoteHspCacheOpt {
  bundleName: string;

  versionCode: string;

  // integratedRemoteHsp相关信息
  integratedRemoteHsps: Map<string, RemoteHspOpt>;
}

const log: OhosLogger = OhosLogger.getLogger('IntegratedHspUtils');

/**
 * 集成态hsp的utils
 */
export class IntegratedHspUtils {
  private integratedHspCache: IntegratedRemoteHspCacheOpt = {
    bundleName: '',
    versionCode: '',
    integratedRemoteHsps: new Map<string, RemoteHspOpt>(),
  };

  private readonly integratedHspCachePath: string;

  constructor(projectModel: ProjectModel) {
    const currentProduct: ProductBuildOpt = findTargetProduct(projectModel);
    this.integratedHspCachePath = path.resolve(projectModel.getCacheIntegratedHspPath(currentProduct.name), BuildArtifactConst.INTEGRATED_HSP_CACHE);
    this.initIntegratedHspCache(projectModel, currentProduct);
  }

  private initIntegratedHspCache(projectModel: ProjectModel, currentProduct: ProductBuildOpt) {
    if (projectModel.isFaMode()) {
      return;
    }
    const appJson: AppOptObj = (projectModel as ProjectModelImpl).getAppRes().getAppResOpt();
    if (!appJson) {
      const appJsonPath = path.resolve(projectModel.getProjectDir(), CommonConst.APP_SCOPE, CommonConst.APP_CONFIG);
      log.printErrorExit('APPJSON5_NOT_FOUND', [appJsonPath]);
    }
    if (!appJson.app) {
      return;
    }
    const appOptFromConfig: AppOpt = cloneDeep(projectOhosConfigManager.getOverrides()?.appOpt);
    const bundleName = appOptFromConfig?.bundleName ?? currentProduct.bundleName ?? appJson.app.bundleName;
    const versionCode = appOptFromConfig?.versionCode ?? currentProduct.versionCode ?? appJson.app.versionCode;
    const defaultIntegratedHspCache = {
      bundleName: bundleName,
      versionCode: versionCode?.toString(),
      integratedRemoteHsps: new Map<string, RemoteHspOpt>(),
    };
    if (!fse.existsSync(this.integratedHspCachePath)) {
      this.integratedHspCache = defaultIntegratedHspCache;
      return;
    }
    const integratedHspCache: any = getJson5Obj(this.integratedHspCachePath);
    const cacheDir = path.dirname(this.integratedHspCachePath);
    if (integratedHspCache.bundleName === bundleName && integratedHspCache.versionCode === versionCode.toString()) {
      const integratedHspNames = fse.readdirSync(path.dirname(this.integratedHspCachePath));
      Object.keys(integratedHspCache.integratedRemoteHsps).forEach((key) => {
        const cache = integratedHspCache.integratedRemoteHsps[key];
        if (
          integratedHspNames.includes(key) &&
          cache?.hspPath &&
          fse.existsSync(cache.hspPath) &&
          fse.existsSync(path.resolve(cacheDir, cache.hspDirName, cache.hspFileName))
        ) {
          defaultIntegratedHspCache.integratedRemoteHsps.set(key, cache);
        }
      });
    }
    this.integratedHspCache = defaultIntegratedHspCache;
  }

  public getIntegratedHspCache() {
    return this.integratedHspCache;
  }

  /**
   * 判断remoteHsp是否需要回填，用于去重
   * @param hspDirName  hsp目录名
   */
  public isNeedIntegrated(hspDirName: string): boolean {
    return !this.integratedHspCache.integratedRemoteHsps.has(hspDirName);
  }

  /**
   * 将需要回填的hsp加入到map中
   *
   * @param integratedRemoteHsp
   */
  public setIntegratedRemoteHsps(integratedRemoteHsp: RemoteHspOpt) {
    this.integratedHspCache.integratedRemoteHsps.set(integratedRemoteHsp.hspDirName, integratedRemoteHsp);
  }

  /**
   * 改变回填hsp的isIntegratedHsp字段为true
   *
   * @param hspDirName
   */
  public changeIntegratedHspStatus(hspDirName: string): void {
    for (const item of this.integratedHspCache.integratedRemoteHsps.values()) {
      if (item.hspDirName === hspDirName) {
        item.isIntegratedHsp = true;
      }
    }
  }

  /**
   * 确认所有hsp都回填后写入集成态hsp的缓存
   */
  public writeIntegratedHspCache(): void {
    if (this.integratedHspCache.integratedRemoteHsps.size === 0) {
      if (fse.existsSync(path.dirname(this.integratedHspCachePath))) {
        fse.removeSync(path.dirname(this.integratedHspCachePath));
      }
      return;
    }
    for (const item of this.integratedHspCache.integratedRemoteHsps.values()) {
      if (!item.isIntegratedHsp) {
        return;
      }
    }
    if (!fse.existsSync(path.dirname(this.integratedHspCachePath))) {
      fse.mkdirSync(path.dirname(this.integratedHspCachePath), { recursive: true });
    }
    fse.writeJsonSync(this.integratedHspCachePath, {
      bundleName: this.integratedHspCache.bundleName,
      versionCode: this.integratedHspCache.versionCode,
      integratedRemoteHsps: Object.fromEntries(this.integratedHspCache.integratedRemoteHsps),
    });
  }

  public resetIntegratedHspCache() {
    this.integratedHspCache = {
      bundleName: '',
      versionCode: '',
      integratedRemoteHsps: new Map<string, RemoteHspOpt>(),
    };
  }
}

/**
 * 生成回填命令行，用于integratedHsp集成态hsp回填数据bundleName和versionCode
 *
 * @param projectModel  工程model
 * @param packageTool 打包工具jar包地址
 * @param inputPath  需要回填的hsp包路径
 * @param outputPath  回填后的输出hsp包路径
 */
export function generateIntegratedHspCommand(projectModel: ProjectModel, packageTool: string, inputPath: string, outputPath: string): string[] {
  const { bundleName, versionCode } = getAppInfoByProject(projectModel);
  const packageOptions = new PackingToolOptions();
  packageOptions.addCalledJarFile(packageTool);
  return packageOptions
    .addMode('packageNormalize')
    .addBundleName(bundleName)
    .addVersionCode(versionCode.toString())
    .addHspList(inputPath)
    .addOutPath(outputPath)
    .build();
}

/**
 * 获取当前工程的bundleName和versionCode字段
 *
 * @param projectModel
 */
export function getAppInfoByProject(projectModel: ProjectModel) {
  const appJson: AppOptObj = (projectModel as ProjectModelImpl).getAppRes().getAppResOpt();
  const appOptFromConfig: AppOpt = cloneDeep(projectOhosConfigManager.getOverrides()?.appOpt);
  const currentProduct: ProductBuildOpt = findTargetProduct(projectModel!);
  const bundleName = appOptFromConfig?.bundleName ?? currentProduct.bundleName ?? appJson.app.bundleName;
  const versionCode = appOptFromConfig?.versionCode ?? currentProduct.versionCode ?? appJson.app.versionCode;
  return { bundleName, versionCode };
}
